using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace zombieArena
{
    /// <summary>
    /// This is the main prototype for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        bool debugMode = false;

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D mapTexture;
        Texture2D playerTexture;
        Texture2D nessBikeTexture;
        Texture2D zombieTexture;
        Texture2D bulTexture;
        Texture2D boomTexture;
        Texture2D whiteSpaceTexture;
        Texture2D cursorTexture;
        Texture2D titleTexture;
        Texture2D pauseScreen;
        Texture2D highscoresTexture;
        Texture2D grenadeTexture;
        Texture2D menuBar;
        Texture2D zombiesLeft;
        Texture2D laserTexture;
        Texture2D[] powerupTexture = new Texture2D[5];
        Texture2D[] zombieTextures = new Texture2D[5];
        Texture2D life;
        Texture2D controls;
        Texture2D letterHolder;
        Map myMap;
        Player player;
        HighScores highscores;
        Texture2D topBar;
        Texture2D[] loadedTextures;

        // cursor
        Cursor cursor;
        Vector2 cursorPosition;
        float cursorDistance = 150;

        float timer = 0f; // keeps track of time
        float interval = 100f; // sets frame rate


        float roundStartTime = 0f;
        float roundMaxTime = 3000f;

        // fps stuff
        float fpsTimer = 0f;
        float zombieTestTimer = 0f;
        float bulletTestTimer = 0f;
        string zombieTestPrint = "";
        string bulletTestPrint = "";
        int fpsCount = 0;
        string fpsPrint = "";

        // temporary weapon stuff
        float shootTimer = 0f;
        bool allowShoot = true;

        float altShootTimer = 0f;
        bool allowAltShoot = true;

        Vector2 bulletDirection = new Vector2(0f, 0f);
        Texture2D bulletSprite;
        int prototype = 0;
        bool prototyping = false;
        int numberOfGuns = 4;

        // testing stuff
        bool freezeZombies = false;
        KeyboardState keyboardState;
        KeyboardState oldKeyboardState;
        bool enableGamePad = true;
        bool gamePadLock = false;
        bool displayDebug = true;
        bool allowEnemyDeath = true;
        bool lockAim = false;
        bool lockMove = false;

        bool unpausePossible = true;

        int hitCount = 0;

        // Animation optimization
        List<Animation> aList;
        Animation a;

        // Audio objects
        AudioEngine audioEngine;
        WaveBank waveBank;
        SoundBank soundBank;
        Cue myLoopingSound = null;
        String[] gunSounds = new String[] { "PistolWav", "MachineGunWav", "ShotgunWav", "Laser", "PistolWav" };

        Rounds round = new Rounds();

        float ZOMBIE_SPAWN = 250f;
        float zombieTimer = 0f;

        //Game state manager
        enum States
        {
            menu,
            playing,
            gameOver,
            pause,
            highscore,
            controls
        }
        States state = new States();

        char[] nameInput;
        int currentCharPos;
        int currentCharASCII;
        bool btnHighscorePressed;
        float charsTimer = 150f;
        float timerCounter = 0f;
        SpriteFont hsFont;

        int currentMenuBtn;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.PreferredBackBufferWidth =  1280;
            graphics.PreferredBackBufferHeight =  720;

            //graphics.PreferredBackBufferWidth = 800;
            //graphics.PreferredBackBufferHeight = 600;

            //graphics.ToggleFullScreen();
            
        }

        
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            audioEngine = new AudioEngine(@"Content\ZombieArenaSounds.xgs");

            //  Assume the default names for the wave and sound bank.  
            //   To change these names, change properties in XACT
            waveBank = new WaveBank(audioEngine, @"Content\Sounds.xwb");
            soundBank = new SoundBank(audioEngine, @"Content\SoundBank.xsb");
            round.nextRound();

            myLoopingSound = soundBank.GetCue("backgroundmusic");
            myLoopingSound.Play();

            base.Initialize();
        }

       
        protected override void LoadContent()
        {
            oldKeyboardState = Keyboard.GetState();

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            mapTexture = Content.Load<Texture2D>("map");
            playerTexture = Content.Load<Texture2D>("gohan2");
            nessBikeTexture = Content.Load<Texture2D>("sprites");
            zombieTexture = Content.Load<Texture2D>("zombie5");
            bulTexture = Content.Load<Texture2D>("bullet");
            boomTexture = Content.Load<Texture2D>("boom");
            grenadeTexture = Content.Load<Texture2D>("grenade");
            whiteSpaceTexture = Content.Load<Texture2D>("whiteSpace");
            cursorTexture = Content.Load<Texture2D>("cursor");
            titleTexture = Content.Load<Texture2D>("titlescreen");
            laserTexture = Content.Load<Texture2D>("laserbullet");
            pauseScreen = Content.Load<Texture2D>("pause");
            powerupTexture[0] = Content.Load<Texture2D>("MBtn");
            powerupTexture[1] = Content.Load<Texture2D>("SBtn");
            powerupTexture[2] = Content.Load<Texture2D>("PBtn");
            powerupTexture[3] = Content.Load<Texture2D>("LBtn");
            powerupTexture[4] = Content.Load<Texture2D>("nuke");

            zombieTextures[0] = Content.Load<Texture2D>("zombie1");
            zombieTextures[1] = Content.Load<Texture2D>("zombie2");
            zombieTextures[2] = Content.Load<Texture2D>("zombie3");
            zombieTextures[3] = Content.Load<Texture2D>("zombie4");
            zombieTextures[4] = Content.Load<Texture2D>("zombie5");

            highscoresTexture = Content.Load<Texture2D>("highscores");
            letterHolder = Content.Load<Texture2D>("letterHolder");
            menuBar = Content.Load<Texture2D>("menuBar");
            hsFont = Content.Load<SpriteFont>("hsfont");
            topBar = Content.Load<Texture2D>("topBar");
            zombiesLeft = Content.Load<Texture2D>("zombiesLeft");
            controls = Content.Load<Texture2D>("controls");

            life = Content.Load<Texture2D>("1Up");
            bulletSprite = bulTexture;

            loadedTextures = new Texture2D[] { boomTexture, whiteSpaceTexture};

            player = new Player(graphics.PreferredBackBufferWidth-300, graphics.PreferredBackBufferHeight, 82, 56, nessBikeTexture);
            myMap = new Map(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight, mapTexture.Width, mapTexture.Height, 0, 0, mapTexture, ref player, ref zombieTextures);

            highscores = new HighScores();

            // lazy bullet texture fix
            myMap.setBulletTexture(bulTexture, laserTexture);

            // add enemies to map
            myMap.newLevel();
            
            player.weapon = new Pistol(bulTexture);
            // grenade
            player.altWeapon = new Grenade(grenadeTexture, grenadeTexture);

            cursor = new Cursor(cursorTexture);
            cursorPosition = new Vector2(0, 0);

            state = States.menu;
            // TODO: use this.Content to load your game content here

            nameInput = new char[3];
            nameInput[0] = ' ';
            nameInput[1] = ' ';
            nameInput[2] = ' ';
            currentCharPos = 0;
            currentCharASCII = 65;
            btnHighscorePressed = false;

            currentMenuBtn = 0;
        }

        public void restartGame()
        {
            roundStartTime = 0f;
            roundMaxTime = 3000f;
            round = new Rounds();
            round.nextRound();
            player = new Player(graphics.PreferredBackBufferWidth - 300, graphics.PreferredBackBufferHeight, 82, 56, nessBikeTexture); ;
            myMap = null;
            player = new Player(mapTexture.Width / 2, mapTexture.Height / 2, 82, 56, nessBikeTexture);
            myMap = new Map(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight, mapTexture.Width, mapTexture.Height, 0, 0, mapTexture, ref player, ref zombieTextures);

            // lazy bullet texture fix
            myMap.setBulletTexture(bulTexture, laserTexture);

            // add enemies to map
            myMap.newLevel();

            // lag spike if I don't do this wtf, lol
            myMap.addEnemy(ref graphics, ref zombieTexture, round.round);
            myMap.clearEnemies();

            player.weapon = new Pistol(bulTexture);
            player.altWeapon = new Grenade(grenadeTexture, grenadeTexture);

            cursor = new Cursor(cursorTexture);
            cursorPosition = new Vector2(0, 0);

            state = States.playing;
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
            mapTexture.Dispose();
            playerTexture.Dispose();
            highscoresTexture.Dispose();
            nessBikeTexture.Dispose();
            zombieTexture.Dispose();
            bulTexture.Dispose();
            boomTexture.Dispose();
            grenadeTexture.Dispose();
            whiteSpaceTexture.Dispose();
            cursorTexture.Dispose();
            titleTexture.Dispose();
            pauseScreen.Dispose();
            powerupTexture[0].Dispose();
            powerupTexture[1].Dispose();
            powerupTexture[2].Dispose();
            powerupTexture[3].Dispose();
            powerupTexture[4].Dispose();
            zombieTextures[0].Dispose();
            zombieTextures[1].Dispose();
            zombieTextures[2].Dispose();
            zombieTextures[3].Dispose();
            zombieTextures[4].Dispose();
            letterHolder.Dispose();
            menuBar.Dispose();
            topBar.Dispose();
            zombiesLeft.Dispose();
            life.Dispose();
        }
       
        protected override void Update(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();

            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            if (keyboardState.IsKeyDown(Keys.Escape))
                this.Exit();

            if (state == States.menu && timerCounter > charsTimer)
            {
                if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y < 0)
                    currentMenuBtn = (currentMenuBtn + 1) % 4;
                if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y > 0)
                    currentMenuBtn = (currentMenuBtn == 0) ? 3 : currentMenuBtn - 1;
                timerCounter = 0f;
            }

            if (state == States.gameOver && timerCounter > charsTimer)
            {
                

                nameInput[currentCharPos] = (char)currentCharASCII;

                if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y > 0)
                    currentCharASCII = (currentCharASCII >= 90) ? 65 : currentCharASCII + 1;

                 if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y < 0)
                     currentCharASCII = (currentCharASCII <= 65) ? 90 : currentCharASCII - 1;

                 if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed && !btnHighscorePressed)
                 {
                     currentCharPos++;
                     btnHighscorePressed = true;
                 }
                if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Released)
                    btnHighscorePressed = false;

                timerCounter = 0f;
               
                if(currentCharPos > 2)
                {
                    highscores.inputScore(new string(nameInput), player.score, round.round);
                    state = States.highscore;
                }
                    

            }
            timerCounter += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            if (state == States.playing)
            {
                // keyboard debug buttons
                keyboardButtons(gameTime);

                // Gamepad/Keyboard movement switch
                if (enableGamePad)
                    gamePadMovement(gameTime);

                keyboardMovement(gameTime);

                // check if timer is more than the chosen interval for sprite animation
                if (timer > interval)
                {
                    player.currentSprite = (player.currentSprite + 1) % 3;
                    timer = 0f;
                }

                updateBullets(ref gameTime);
                bulletTestTimer += myMap.bulletCollision(ref allowEnemyDeath, ref gameTime);
                zombieTestTimer += myMap.moveEnemies(ref spriteBatch, ref freezeZombies, ref gameTime);
                if (player.invulnerable && hitCount == 0)
                {
                    hitCount++;
                    soundBank.PlayCue("PlayerHit");
                }
                if(!player.invulnerable )
                    hitCount = 0;
                updateAnimations(ref gameTime);

                fpsCounter(gameTime);
                
                handleZombies(gameTime);

                player.updateInvulnerable(ref gameTime);
                
                player.updateColor();

                // cursor
                cursorPosition = player.position;
                cursorPosition.X += player.aimDirection.X * cursorDistance;
                cursorPosition.Y += player.aimDirection.Y * cursorDistance;

                cursor.move(cursorPosition);

                if (player.invulnerable && player.lives < 0)
                {
                    soundBank.PlayCue("GameOver");
                       
                    state = States.gameOver;
                    player.invulnerable = false;
                }

                if (myMap.pickedUp)
                {
                    if (myMap.pickedUpID == 4)
                        soundBank.PlayCue("Nuke");
                    else
                        soundBank.PlayCue("PowerUp");

                }
                if (myMap.extraLifeSound)
                {
                    soundBank.PlayCue("ExtraLife");
                    myMap.extraLifeSound = false;
                }

                oldKeyboardState = keyboardState;
            }
            else if (state == States.highscore)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Released)
                    btnHighscorePressed = false;

                if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed && !btnHighscorePressed)
                {
                    state = States.menu;
                    currentCharPos = 0;
                    btnHighscorePressed = true;
                }

                highscores.drawHighScores(highscoresTexture, ref spriteBatch, hsFont);
            }
            else if (state == States.menu)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Released)
                    btnHighscorePressed = false;
                if ((GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Space)) && !btnHighscorePressed && currentMenuBtn == 0)
                    restartGame();
                if ((GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Space)) && !btnHighscorePressed && currentMenuBtn == 1)
                {
                    state = States.highscore;
                    btnHighscorePressed = true;
                    highscores.drawHighScores(highscoresTexture, ref spriteBatch, hsFont);
                }
                if ((GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Space)) && !btnHighscorePressed && currentMenuBtn == 2)
                    state = States.controls;
                if ((GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Space)) && !btnHighscorePressed && currentMenuBtn == 3)
                    this.Exit();
            }
            if (state == States.controls && GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed)
                state = States.menu;

            //Pause Game Logic
            if (state == States.playing && GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Released)
                unpausePossible = true;
            if (state == States.playing && unpausePossible && GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Pressed)
            {
                state = States.pause;
                unpausePossible = false;
            }
            if (state == States.pause && GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Released)
                unpausePossible = true;
            if (state == States.pause && unpausePossible && GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Pressed)
            {
                state = States.playing;
                unpausePossible = false;
            }
            if (state == States.pause && GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Pressed)
            {
                restartGame();
                state = States.menu;
            }
           

            base.Update(gameTime);
        }

       
        protected override void Draw(GameTime gameTime)
        {
            if (state == States.playing)
                drawGame();
            else if (state == States.gameOver)
                drawGameOver();
            else if (state == States.menu)
                drawMenu();
            else if (state == States.pause)
                drawPause();
            else if (state == States.controls)
                drawControls();
            base.Draw(gameTime);
        }

        // updates the in game timer
        protected void updateTimer(GameTime gameTime)
        {
            timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds; //Increase the timer by the number of milliseconds since update was last called
        }
        // updates FPS counter
        protected void fpsCounter(GameTime gameTime)
        {
            fpsTimer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            if (fpsTimer > 1000)
            {
                fpsPrint = fpsCount.ToString();
                zombieTestPrint = zombieTestTimer.ToString();
                bulletTestPrint = bulletTestTimer.ToString();
                zombieTestTimer = 0;
                bulletTestTimer = 0;
                fpsTimer = 0f;
                fpsCount = 0;
            }
        }

        private void updateBullets(ref GameTime gameTime)
        {
            // rate of fire counter
            if (!allowShoot)
            {
                shootTimer += gameTime.ElapsedGameTime.Milliseconds;
                if (shootTimer > player.weapon.rateOfFire)
                {
                    allowShoot = true;
                    shootTimer = 0f;
                }
            }

            /*
            if (!allowAltShoot)
            {
                altShootTimer += gameTime.ElapsedGameTime.Milliseconds;
                if (altShootTimer > player.weapon.rateOfFire)
                {
                    allowAltShoot = true;
                    altShootTimer = 0f;
                }
            }*/
        }

        int gunType = 0;
        public void gamePadMovement(GameTime gameTime)
        {
            float sensitivity = 0.1f;

            float playerMoveX = GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X;
            float playerMoveY = -GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y;

            player.moveDirection = new Vector2(playerMoveX, playerMoveY);


            Vector2 newMove = new Vector2(playerMoveX, playerMoveY);
            player.moveDirection = newMove;

            myMap.movePlayer();
            newMove.Normalize();
            player.moveDirection = newMove;
            //if (Math.Abs(playerMoveX) > 0 || Math.Abs(playerMoveY) > 0)
                //player.aimDirection = newMove;
            playerMoveX = player.moveDirection.X;
            playerMoveY = player.moveDirection.Y;
            
            

            #region old
            /*
            // down
            if (playerMoveY >= 0.5)
            {
                player.spriteRow = 0;
                updateTimer(gameTime);
            }
            // up
            else if (playerMoveY <= -0.5)
            {
                player.spriteRow = 2;
                updateTimer(gameTime);
            }
            // left
            else if (playerMoveX <= -0.5)
            {
                player.spriteRow = 3;
                updateTimer(gameTime);
            }
            // right
            else if (playerMoveX >= 0.5)
            {
                player.spriteRow = 1;
                updateTimer(gameTime);
            }*/
            #endregion

            // down
            if (playerMoveY >= 0.75 && playerMoveY <= 1.0)
            {
                //player.spriteRow = 0;
                updateTimer(gameTime);
            }
            // down left
            else if (playerMoveY >= 0.5 && playerMoveY <= 0.75 && playerMoveX >= -0.75 && playerMoveX <= -0.25)
            {
                //player.spriteRow = 4;
                updateTimer(gameTime);
            }
            // down right
            else if (playerMoveY >= 0.5 && playerMoveY <= 0.75 && playerMoveX <= 0.75 && playerMoveX >= 0.25)
            {
                //player.spriteRow = 5;
                updateTimer(gameTime);
            }
            // up
            else if (playerMoveY <= -0.75 && playerMoveY >= -1.0)
            {
                //player.spriteRow = 1;
                updateTimer(gameTime);
            }
            // up left
            else if (playerMoveY <= -0.5 && playerMoveY >= -0.75 && playerMoveX >= -0.75 && playerMoveX <= -0.25)
            {
                //player.spriteRow = 6;
                updateTimer(gameTime);
            }
            // up right
            else if (playerMoveY <= -0.5 && playerMoveY >= -0.75 && playerMoveX <= 0.75 && playerMoveX >= 0.25)
            {
                //player.spriteRow = 7;
                updateTimer(gameTime);
            }
            // left
            else if (playerMoveX <= -0.75 && playerMoveX >= -1.0)
            {
                //player.spriteRow = 3;
                updateTimer(gameTime);
            }
            // right
            else if (playerMoveX >= 0.75 && playerMoveX <= 1.0)
            {
                //player.spriteRow = 2;
                updateTimer(gameTime);
            }
            

            if (!gamePadLock)
            {

                if (debugMode)
                {
                    // Change weapon
                    if (GamePad.GetState(PlayerIndex.One).Buttons.LeftShoulder == ButtonState.Pressed)
                    {
                        gunType--;
                        if (gunType < 0)
                            gunType = numberOfGuns;
                        changeWeapon();
                    }

                    if (GamePad.GetState(PlayerIndex.One).Buttons.RightShoulder == ButtonState.Pressed)
                    {
                        gunType++;
                        if (gunType > numberOfGuns)
                            gunType = 0;
                        changeWeapon();
                    }

                    if (GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Pressed)
                    {
                        if (!prototyping)
                        {
                            player.weapon = new SuperShotgun(bulTexture);
                            player.altWeapon = new SuperGrenade(bulTexture);
                            player.lives = 99;
                            prototyping = true;
                        }
                        else
                        {
                            player.weapon = new Pistol(bulTexture);
                            player.altWeapon = new Grenade(grenadeTexture, grenadeTexture);
                            player.lives = 3;
                            prototyping = false;
                        }

                    }
                }
                
                /*
                if (GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Pressed)
                {
                    state = States.pause;
                }
                */
                gamePadLock = true;
            }

            


            if (GamePad.GetState(PlayerIndex.One).Buttons.RightShoulder == ButtonState.Released && GamePad.GetState(PlayerIndex.One).Buttons.LeftShoulder == ButtonState.Released
                && GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Released)
            {
                gamePadLock = false;
            }

            float playerAimX = GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X;
            float playerAimY = -GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y;


            if (Math.Abs(playerAimX) > sensitivity || Math.Abs(playerAimY) > sensitivity)

            if (Math.Abs(playerAimX) > 0 || Math.Abs(playerAimY) > 0)

            {
                Vector2 newDirection = new Vector2(playerAimX, playerAimY);
                newDirection.Normalize();
                player.aimDirection = newDirection;
                player.aimDirection.Normalize();
                playerAimX = player.aimDirection.X;
                playerAimY = player.aimDirection.Y;

                #region old
                /*
            if (playerAimY >= 0.5)
            {
                player.spriteRow = 0;
            }
            else if (playerAimY <= -0.5)
            {
                player.spriteRow = 2;
            }
            else if (playerAimX <= -0.5)
            {
                player.spriteRow = 3;
            }
            else if (playerAimX >= 0.5)
            {
                player.spriteRow = 1;
            }
             * */
                #endregion

                // down
                if (playerAimY >= 0.75 && playerAimY <= 1.0)
                {
                    player.spriteRow = 0;
                }
                // down left
                else if (playerAimY >= 0.5 && playerAimY <= 0.75 && playerAimX >= -0.75 && playerAimX <= -0.25)
                {
                    player.spriteRow = 4;
                }
                // down right
                else if (playerAimY >= 0.5 && playerAimY <= 0.75 && playerAimX <= 0.75 && playerAimX >= 0.25)
                {
                    player.spriteRow = 5;
                }
                // up
                else if (playerAimY <= -0.75 && playerAimY >= -1.0)
                {
                    player.spriteRow = 1;
                }
                // up left
                else if (playerAimY <= -0.5 && playerAimY >= -0.75 && playerAimX >= -0.75 && playerAimX <= -0.25)
                {
                    player.spriteRow = 6;
                }
                // up right
                else if (playerAimY <= -0.5 && playerAimY >= -0.75 && playerAimX <= 0.75 && playerAimX >= 0.25)
                {
                    player.spriteRow = 7;
                }
                // left
                else if (playerAimX <= -0.75 && playerAimX >= -1.0)
                {
                    player.spriteRow = 3;
                }
                // right
                else if (playerAimX >= 0.75 && playerAimX <= 1.0)
                {
                    player.spriteRow = 2;
                }
            }

            
            // Shooting
            if (GamePad.GetState(PlayerIndex.One).Triggers.Right > sensitivity)
            {
                if (allowShoot)
                {
                    player.shoot(myMap, prototype, bulTexture);
                    int soundIndex = player.weapon.soundIndex;
                    if (soundIndex < 0 || soundIndex > gunSounds.Length - 1)
                        soundIndex = 0;
                    soundBank.PlayCue(gunSounds[soundIndex]);




                    if (player.weapon.ammo <= 0)
                    {
                        gunType = 0;
                        player.weapon = new Pistol(bulTexture);
                    }
                    allowShoot = false;
                }
            }

            if (GamePad.GetState(PlayerIndex.One).Triggers.Left > sensitivity)
            {
                if (allowAltShoot)
                {
                    if (player.altWeapon.ammo > 0)
                    {
                        soundBank.PlayCue("Grenade");
                        player.altShoot(myMap, prototype, bulTexture);
                    }
                    

                    allowAltShoot = false;
                }
            }

            if (GamePad.GetState(PlayerIndex.One).Triggers.Left < sensitivity)
            {
                allowAltShoot = true;
            }
        }

        public void changeWeapon()
        {
            switch (gunType)
            {
                case 0:
                    prototype = 0;
                    player.weapon = new Pistol(bulTexture);
                    break;
                case 1:
                    prototype = 0;
                    player.weapon = new MachineGun(bulTexture);
                    break;
                case 2:
                    prototype = 0;
                    player.weapon = new Shotgun(bulTexture);
                    break;
                case 3:
                    prototype = 0;
                    player.weapon = new Laser(laserTexture);
                    break;
                case 4:
                    prototype = 0;
                    player.weapon = new Spread(bulTexture);
                    break;
                default:
                    prototype = 0;
                    player.weapon = new Pistol(bulTexture);
                    break;
            }
        }

        #region keyboard
        public void keyboardMovement(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();

            if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.X))
            {
                lockAim = true;
            }
            else if (keyboardState.IsKeyUp(Keys.LeftShift) && keyboardState.IsKeyUp(Keys.X))
            {
                lockAim = false;
            }

            if (keyboardState.IsKeyDown(Keys.C))
            {
                lockMove = true;
            }
            else if (keyboardState.IsKeyUp(Keys.C))
            {
                lockMove = false;
            }

            if (keyboardState.IsKeyDown(Keys.Down) && keyboardState.IsKeyDown(Keys.Left))
            {
                player.moveDirection = new Vector2(-1, 1);
                player.moveDirection.Normalize();
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(-1, 1);
                    player.spriteRow = 4;
                }
                player.aimDirection.Normalize();
                if (!lockMove)
                    myMap.movePlayer();
                updateTimer(gameTime);
            }
            else if (keyboardState.IsKeyDown(Keys.Down) && keyboardState.IsKeyDown(Keys.Right))
            {
                player.moveDirection = new Vector2(1, 1);
                player.moveDirection.Normalize();
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(1, 1);
                    player.spriteRow = 5;
                }
                player.aimDirection.Normalize();
                if (!lockMove)
                    myMap.movePlayer();
                
                updateTimer(gameTime);
            }
            else if (keyboardState.IsKeyDown(Keys.Up) && keyboardState.IsKeyDown(Keys.Left))
            {
                player.moveDirection = new Vector2(-1, -1);
                player.moveDirection.Normalize();
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(-1, -1);
                    player.spriteRow = 6;
                }
                player.aimDirection.Normalize();
                if (!lockMove)
                    myMap.movePlayer();

                updateTimer(gameTime);
            }
            else if (keyboardState.IsKeyDown(Keys.Up) && keyboardState.IsKeyDown(Keys.Right))
            {
                player.moveDirection = new Vector2(1, -1);
                player.moveDirection.Normalize();
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(1, -1);
                    player.spriteRow = 7;
                }
                player.aimDirection.Normalize();
                if (!lockMove)
                    myMap.movePlayer();

                updateTimer(gameTime);
            }

            else if (keyboardState.IsKeyDown(Keys.Up))
            {
                player.moveDirection = new Vector2(0, -1);
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(0, -1);
                    player.spriteRow = 1;
                }
                player.aimDirection.Normalize();
                if (!lockMove)
                    myMap.movePlayer();
                
                updateTimer(gameTime);
            }
            else if (keyboardState.IsKeyDown(Keys.Down))
            {
                player.moveDirection = new Vector2(0, 1);
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(0, 1);
                    player.spriteRow = 0;
                }
                player.aimDirection.Normalize();
                if (!lockMove)
                    myMap.movePlayer();
                
                updateTimer(gameTime);
            }
            else if (keyboardState.IsKeyDown(Keys.Right))
            {
                player.moveDirection = new Vector2(1, 0);
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(1, 0);
                    player.spriteRow = 2;
                }
                if (!lockMove)
                    myMap.movePlayer();
                
                updateTimer(gameTime);
            }
            else if (keyboardState.IsKeyDown(Keys.Left))
            {
                player.moveDirection = new Vector2(-1, 0);
                if (!lockAim)
                {
                    player.aimDirection = new Vector2(-1, 0);
                    player.spriteRow = 3;
                }
                if (!lockMove)
                    myMap.movePlayer();
                
                updateTimer(gameTime);
            }
            if (keyboardState.IsKeyDown(Keys.Space) || keyboardState.IsKeyDown(Keys.LeftControl) || keyboardState.IsKeyDown(Keys.Z))
            {
                if (allowShoot)
                {
                    player.shoot(myMap, prototype, bulTexture);
                    allowShoot = false;
                }
            }
            
        }

        public void keyboardButtons(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();

            // Keyboard lock to stop repeating buttons
            if (keyboardState != oldKeyboardState)
            {
                if (!prototyping)
                {
                    // pistol
                    if (keyboardState.IsKeyDown(Keys.D1))
                    {
                        prototype = 0;
                        player.weapon = new Pistol(bulTexture);
                    }
                    // machinegun
                    if (keyboardState.IsKeyDown(Keys.D2))
                    {
                        prototype = 0;
                        player.weapon = new MachineGun(bulTexture);
                    }
                    // shotgun
                    if (keyboardState.IsKeyDown(Keys.D3))
                    {
                        prototype = 0;
                        player.weapon = new Shotgun(bulTexture);
                    }
                    // LASERZ
                    if (keyboardState.IsKeyDown(Keys.D4))
                    {
                        prototype = 0;
                        player.weapon = new Laser(bulTexture);
                    }
                }
                else
                {
                    // prototypes
                    if (keyboardState.IsKeyDown(Keys.D1))
                    {
                        prototype = 1;
                        player.weapon = new Weapon(bulTexture, prototype);
                    }
                    if (keyboardState.IsKeyDown(Keys.D2))
                    {
                        prototype = 2;
                        player.weapon = new Weapon(bulTexture, prototype);
                    }
                    if (keyboardState.IsKeyDown(Keys.D3))
                    {
                        prototype = 3;
                        player.weapon = new Weapon(bulTexture, prototype);
                    }
                    if (keyboardState.IsKeyDown(Keys.D4))
                    {
                        prototype = 4;
                        player.weapon = new Weapon(bulTexture, prototype);
                    }
                    if (keyboardState.IsKeyDown(Keys.D5))
                    {
                        prototype = 5;
                        player.weapon = new Weapon(bulTexture, prototype);
                    }
                }
                // restart zombies
                if (keyboardState.IsKeyDown(Keys.R))
                {
                    myMap.clearEnemies();
                }
                // freeze zombies
                if (keyboardState.IsKeyDown(Keys.S))
                {
                    freezeZombies = !freezeZombies;
                }
                if (keyboardState.IsKeyDown(Keys.G))
                {
                    enableGamePad = !enableGamePad;
                }
                if (keyboardState.IsKeyDown(Keys.D))
                {
                    allowEnemyDeath = !allowEnemyDeath;
                }
                if (keyboardState.IsKeyDown(Keys.Q))
                {
                    displayDebug = !displayDebug;
                }
                if (keyboardState.IsKeyDown(Keys.P))
                {
                    prototyping = !prototyping;
                    if (!prototyping)
                    {
                        prototype = 0;
                        player.weapon = new Pistol(bulTexture);
                    }
                    else
                    {
                        prototype = 1;
                        player.weapon = new Weapon(bulTexture, prototype);
                    }
                }
            }
        }
        #endregion

        /// <summary>
        /// Handles all the actions with zombies
        /// </summary>
        public void handleZombies(GameTime gameTime)
        {
            zombieTimer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
            roundStartTime += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
            if (round.spawnedEnemies < round.totalEnemies && myMap.zombiesAlive < myMap.maxZombies() && zombieTimer >= ZOMBIE_SPAWN && roundStartTime > roundMaxTime)
            {
                zombieTimer = 0f;
                round.spawnEnemy();
                myMap.addEnemy(ref graphics, ref zombieTexture, round.round);
            }

            if (round.spawnedEnemies == round.totalEnemies && myMap.zombiesAlive == 0)
            {
                myMap.zombiesKilled = 0;
                round.nextRound();

                // fade dead zombies
                int animCount = 0;
                // dead zombies list
                aList = myMap.animationList[0];
                while (animCount < aList.Count)
                {
                    a = aList[animCount];
                    a.infinite = false;
                    if (a.nextFrame != null)
                        a.nextFrame.infinite = false;
                    ++animCount;
                }
                roundStartTime = 0;
                player.altWeapon.ammo = 2;
                ZOMBIE_SPAWN -= 2;
            }
        }

        // optimize
        Vector2 enemyscreenpos;

        /// <summary>
        /// Draws all the zombies
        /// </summary>
        public void drawZombies()
        {
            for (int i = 0; i < myMap.arraySize; i++)
            {
                for (int j = 0; j < myMap.arraySize; j++)
                {
                    foreach (Enemy enemy in myMap.enemyList[j, i])
                    {
                        // optimize
                        enemyscreenpos = enemy.position;
                        enemyscreenpos.X -= myMap.viewPort.X;
                        enemyscreenpos.Y -= myMap.viewPort.Y;

                        enemy.draw(ref enemyscreenpos, ref spriteBatch);
                    }
                }
            }
        }

        


        /// <summary>
        /// Draws the powerups
        /// </summary>
        public void drawPowerups()
        {
            foreach (Powerup p in myMap.powerupList)
            {
                Vector2 newPos = new Vector2(p.position.X - myMap.viewPort.X, p.position.Y - myMap.viewPort.Y);
                p.Draw(spriteBatch, powerupTexture[p.id], newPos);
            }
        }

        /// <summary>
        /// Draws all the game components
        /// </summary>
        public void drawGame()
        {
            GraphicsDevice.Clear(Color.Black);
            fpsCount++;
            spriteBatch.Begin();

            Rectangle viewPort = myMap.viewPort;
            myMap.draw(ref spriteBatch);



            int animListCount = 0;
            int animCount = 0;
            while (animListCount < myMap.animationList.Count)
            {
                animCount = 0;
                aList = myMap.animationList[animListCount];
                while (animCount < aList.Count)
                {
                    a = aList[animCount];
                    if (a.textureReference == -1)
                        a.draw(ref spriteBatch, ref viewPort);
                    else
                        a.draw(ref spriteBatch, ref viewPort, ref loadedTextures[a.textureReference]);
                    ++animCount;
                }
                animListCount++;
            }
            drawPowerups();
            drawZombies();

            
            foreach (Bullet bul in myMap.bulletList)
                bul.Draw(ref spriteBatch, ref viewPort);
            player.draw(ref spriteBatch, ref viewPort);
            if (prototype == 4)
                player.weapon.prototype4idle(player.position, player.aimDirection, myMap, spriteBatch);

            cursor.draw(ref spriteBatch, ref viewPort);

            spriteBatch.Draw(topBar, new Vector2(0, 0), Color.White);

            // draw fps counter
            spriteBatch.DrawString(hsFont, fpsPrint, new Vector2(graphics.PreferredBackBufferWidth - 250, 0), Color.White);
            spriteBatch.DrawString(hsFont, player.weapon.name, new Vector2(45, 15), Color.White);

            if (player.weapon.ammo < 500)
                spriteBatch.DrawString(hsFont, "Ammo: " + player.weapon.ammo, new Vector2(200, 15), Color.White);
            else
            {
                spriteBatch.DrawString(hsFont, "Ammo: ", new Vector2(200, 15), Color.White);
                spriteBatch.DrawString(hsFont, "O", new Vector2(275, 15), Color.White);
                spriteBatch.DrawString(hsFont, "O", new Vector2(284, 15), Color.White);
            }
            spriteBatch.DrawString(hsFont, "Grenades: " + player.altWeapon.ammo, new Vector2(350, 15), Color.White);
            spriteBatch.DrawString(hsFont, "Round: " + round.round, new Vector2(500, 15), Color.White);
            spriteBatch.DrawString(hsFont, "Score: " + myMap.player.score, new Vector2(1100, 15), Color.White);
            #region debug
            /*spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Debug screen (Q): " + displayDebug, new Vector2(0, 40), Color.White);
            if (displayDebug)
            {
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Freeze zombies(S): " + round.totalEnemies, new Vector2(0, 60), Color.White);
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Zombie death (D): " + allowEnemyDeath, new Vector2(0, 80), Color.White);
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Gamepad (G): " + enableGamePad, new Vector2(0, 100), Color.White);
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Bullets: " + myMap.bulletList.Count.ToString(), new Vector2(0, 120), Color.White);
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Zombies: " + myMap.zombiesAlive, new Vector2(0, 140), Color.White);
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Zombie collisions: " + zombieTestPrint + " / " + myMap.zombieCollisionCount, new Vector2(0, 160), Color.White);
                spriteBatch.DrawString(Content.Load<SpriteFont>("font"), "Bullet collisions: " + bulletTestPrint + " / " + myMap.bulletCollisionCount, new Vector2(0, 180), Color.White);
            }*/
            #endregion
            spriteBatch.Draw(life, new Vector2(710, 15), Color.White);
            spriteBatch.DrawString(hsFont, "x" + player.lives, new Vector2(735, 15), Color.White);
            spriteBatch.Draw(zombiesLeft, new Vector2(800, 15), Color.White);
            spriteBatch.DrawString(hsFont, "x" + (round.remainingEnemies - myMap.zombiesKilled), new Vector2(825, 15), Color.White);


            if(roundStartTime < roundMaxTime)
                spriteBatch.DrawString(Content.Load<SpriteFont>("nextRound"), "ROUND " + round.round, 
                    new Vector2(graphics.PreferredBackBufferWidth/2 - 150, graphics.PreferredBackBufferHeight/2 - 25), Color.Red);



            spriteBatch.End();
        }

        /// <summary>
        /// Draws the game over screen components
        /// </summary>
        public void drawGameOver()
        {
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();

                spriteBatch.Draw(letterHolder, new Vector2(graphics.PreferredBackBufferWidth / 2 - 70, graphics.PreferredBackBufferHeight / 2 + 145), Color.White);
                spriteBatch.Draw(letterHolder, new Vector2(graphics.PreferredBackBufferWidth / 2 - 20, graphics.PreferredBackBufferHeight / 2 + 145), Color.White);
                spriteBatch.Draw(letterHolder, new Vector2(graphics.PreferredBackBufferWidth / 2 + 30, graphics.PreferredBackBufferHeight / 2 + 145), Color.White);

                spriteBatch.DrawString(hsFont, "Game Over", new Vector2(graphics.PreferredBackBufferWidth / 2 - 50, graphics.PreferredBackBufferHeight / 2 - 50), Color.White);
                spriteBatch.DrawString(hsFont, "Score: " + player.score.ToString(), new Vector2(graphics.PreferredBackBufferWidth / 2 - 50, graphics.PreferredBackBufferHeight / 2), Color.White);
                spriteBatch.DrawString(hsFont, "Select Name", new Vector2(graphics.PreferredBackBufferWidth / 2 - 70, graphics.PreferredBackBufferHeight / 2 + 100), Color.White);
                spriteBatch.DrawString(hsFont, ""+nameInput[0], new Vector2(graphics.PreferredBackBufferWidth / 2 - 60, graphics.PreferredBackBufferHeight / 2 + 150), Color.White);
                spriteBatch.DrawString(hsFont, "" + nameInput[1], new Vector2(graphics.PreferredBackBufferWidth / 2 - 10, graphics.PreferredBackBufferHeight / 2 + 150), Color.White);
                spriteBatch.DrawString(hsFont, "" + nameInput[2], new Vector2(graphics.PreferredBackBufferWidth / 2 + 40, graphics.PreferredBackBufferHeight / 2 + 150), Color.White);
            spriteBatch.End();
        }

        public void drawControls()
        {
            spriteBatch.Begin();
            spriteBatch.Draw(controls, new Vector2(0, 0), Color.White);
            spriteBatch.End();
        }

        /// <summary>
        /// Draws menu items
        /// </summary>
        public void drawMenu()
        {
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();
            spriteBatch.Draw(titleTexture, new Vector2(0, 0), Color.White);
            spriteBatch.Draw(menuBar, new Vector2(635, 475 + 60 * currentMenuBtn), Color.White);
            spriteBatch.End();
        }

        public void drawPause()
        {
            drawGame();
            spriteBatch.Begin();
            spriteBatch.Draw(pauseScreen, new Vector2(0, 0), Color.White);
            spriteBatch.End();
        }

        public void updateAnimations(ref GameTime gameTime)
        {

            int animListCount = 0;
            int animCount = 0;
            while(animListCount < myMap.animationList.Count)
            {
                animCount = 0;
                aList = myMap.animationList[animListCount];
                while (animCount < aList.Count)
                {
                    a = aList[animCount];
                    a.update(ref gameTime);
                    if (a.lifeTime > a.maxLifeTime)
                    {
                        aList.Remove(a);
                        if (a.nextFrame != null)
                        {
                            aList.Add(a.nextFrame);
                        }
                        else
                            --animCount;
                    }
                    ++animCount;
                }
                animListCount++;
            }
        }
    }
}
